/**
 * 
 */
package fr.ece.ing4.si.mc.gui;

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Map;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import fr.ece.ing4.si.mc.MonteCarlo.MonteCarloAbstract;

/**
 * @author Cesar Berezowski, Gaspard Peyrot
 */
public class MainWindow extends JFrame {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	/**
	 * Quit button
	 */
	private JButton quit;
	/**
	 * Button to launch computing
	 */
	private JButton launch;
	/**
	 * Area where the data set is displayed
	 */
	private JTextArea dataDisplayer;
	/**
	 * Field to choose the number of simulations
	 */
	private JTextField nsimulationField;
	/**
	 * Field to choose the number of steps
	 */
	private JTextField nstepsField;
	/**
	 * List to choose the data set
	 */
	private JComboBox dataChooseList;
	/**
	 * List to choose between single or multi threaded method
	 */
	private JComboBox methodChooseList;
	/**
	 * List to choose between put and call computation
	 */
	private JComboBox calculationChooseList;
	/**
	 * HashMap containing the data sets
	 */
	private Map<Integer, double[]> values;
	/**
	 * Variable to designate whether to use single or multi threading
	 */
	private String type;
	/**
	 * Variable to designate whether to use put or call computing
	 */
	private String callPutFlag;
	/**
	 * Variable to designate the number of simulations to do
	 */
	private int nSimulations;
	/**
	 * Variable to designate the number of steps to use
	 */
	private int nSteps;
	/**
	 * Pointer on this object to send to the result window
	 */
	private MainWindow w = this;
	/**
	 * ResultWindow object to initialize once launch is clicked
	 */
	private ResultWindow r;

	/**
	 * Window default constructor
	 */
	public MainWindow(Map<Integer, double[]> values) {
		super();
		this.values = values;
		this.build();
	}
	
	/**
	 * Building window
	 */
	private void build(){
		setTitle("Monte Carlo");
		setSize(500, 500);
		setLocationRelativeTo(null);
		setResizable(false);
		setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		setContentPane(buildContentPanel());
	}
	
	/**
	 * Creation of window's panel and components
	 * @return JPanel
	 */
	private JPanel buildContentPanel(){
		
		// Initialization of necessary variables
		JPanel p = new JPanel();
		GridBagConstraints c = new GridBagConstraints();
		String[] methodType = { "Single threaded", "Multi threaded" };
		String[] dataType= new String[values.size()];
		String[] calculationType = { "Put", "Call" };
		Color color = new Color(232, 232, 232);
		
		for(int i = 0; i < values.size(); i++){
			dataType[i] = "Set " + (i+1);
		}
		
		// Setting the layout
		p.setLayout(new GridBagLayout());
		
		// JLabel hello : creation and adding to the layout
		JLabel hello = new JLabel();
		hello.setText("Welcome to the Monte Carlo app !");
		c.insets = new Insets(10, 5, 10, 5);
		c.gridwidth = 2;
		c.gridx = 0;
		c.gridy = 0;
		p.add(hello, c);
		
		// JLabel methodChooseText : creation and adding to the layout
		JLabel methodChooseText = new JLabel();
		methodChooseText.setText("Please choose a computing method : ");
		c.anchor = GridBagConstraints.EAST;
		c.gridwidth = 1;
		c.gridx = 0;
		c.gridy = 1;
		p.add(methodChooseText, c);
		
		// JComboBox methodChooseList : creation, initialization and adding to the layout
		// Used to choose between multi and single threaded
		methodChooseList = new JComboBox(methodType);
		this.setMethodChooseListListener();
		this.setMultiValue(methodChooseList.getSelectedIndex());
		c.anchor = GridBagConstraints.WEST;
		c.gridx = 1;
		c.gridy = 1;
		p.add(methodChooseList, c);
		
		// JLabel calculationChooseText : creation, initialization and adding to the layout
		JLabel calculationChooseText = new JLabel("Please choose a calculation method : ");
		c.anchor = GridBagConstraints.EAST;
		c.gridx = 0;
		c.gridy = 2;
		p.add(calculationChooseText, c);
		
		// JComboBox calculationChooseList : creation, initialization and adding to the layout
		// Used to choose between put and call
		calculationChooseList = new JComboBox(calculationType);
		this.setCalculationChooseListListener();
		this.setCallPutFlagValue(calculationChooseList.getSelectedIndex());
		c.anchor = GridBagConstraints.WEST;
		c.gridx = 1;
		c.gridy = 2;
		p.add(calculationChooseList, c);
		
		// JLabel dataChooseText : creation, initialization and adding to the layout
		JLabel dataChooseText = new JLabel("Please choose a set of data : ");
		c.anchor = GridBagConstraints.EAST;
		c.gridx = 0;
		c.gridy = 3;
		p.add(dataChooseText, c);
		
		// JComboBox dataChooseList : creation, initialization and adding to the layout
		// Used to choose the data set
		dataChooseList = new JComboBox(dataType);
		this.setDataChooseListListener();
		c.anchor = GridBagConstraints.WEST;
		c.gridx = 1;
		c.gridy = 3;
		p.add(dataChooseList, c);
		
		// JTextArea dataDisplayer : creation, initialization and adding to the layout
		// Used to display the data set
		dataDisplayer = new JTextArea();
		dataDisplayer.setBackground(color);
		this.displayDataAtIndex(dataChooseList.getSelectedIndex() + 1);
		c.anchor = GridBagConstraints.CENTER;
		c.gridwidth = 2;
		c.gridx = 0;
		c.gridy = 4;
		p.add(dataDisplayer, c);
		
		// JLabel nSimulationText : creation, initialization and adding to the layout
		JLabel nsimulationText = new JLabel("Number of simulations");
		c.anchor = GridBagConstraints.EAST;
		c.gridwidth = 1;
		c.gridx = 0;
		c.gridy = 5;
		p.add(nsimulationText, c);
		
		// JTextField nsimulationField : creation, initialization and adding to the layout
		// Used to choose the number of simulations
		nsimulationField = new JTextField();
		nsimulationField.setText("000100000");
		c.anchor = GridBagConstraints.WEST;
		c.gridx = 1;
		c.gridy = 5;
		p.add(nsimulationField, c);
		
		// JLabel nstepsText : creation, initialization and adding to the layout
		JLabel nstepsText = new JLabel("Number of steps");
		c.anchor = GridBagConstraints.EAST;
		c.gridwidth = 1;
		c.gridx = 0;
		c.gridy = 6;
		p.add(nstepsText, c);

		// JTextField nstepsField : creation, initialization and adding to the layout
		// Used to choose the number of steps
		nstepsField = new JTextField();
		nstepsField.setText("000000168");
		c.anchor = GridBagConstraints.WEST;
		c.gridx = 1;
		c.gridy = 6;
		p.add(nstepsField, c);
		
		// JButton launch : creation, initialization and adding to the layout
		// Adding the listener
		launch = new JButton("Launch");
		setLaunchListener();
		c.anchor = GridBagConstraints.EAST;
		c.gridx = 0;
		c.gridy = 7;
		p.add(launch, c);
		
		// JButton quit : creation, initialization and adding to the layout
		// Adding the listener
		quit = new JButton("Quit");
		setQuitListener();
		c.anchor = GridBagConstraints.WEST;
		c.gridx = 1;
		c.gridy = 7;
		p.add(quit, c);
		
		return p;
	}

	/**
	 * Adds the listener on quit button
	 */
	private void setQuitListener(){
		quit.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				
				w.dispose();
				System.exit(0);
				
			}  });
	}
	
	/**
	 * Adds the listener to the methodChooseList JComboBox
	 * Calls setMultiValue with the selected index
	 */
	private void setMethodChooseListListener(){
		methodChooseList.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent e) {
				
				setMultiValue(methodChooseList.getSelectedIndex());
				
			}
			
		});
	}
	
	/**
	 * Sets the value of Boolean multi depending in JComboBox methodChooseList selected index
	 * @param index : JComboBox methodChooseList selected index
	 */
	private void setMultiValue(int index){
		
		if(index == 0) this.type = "single";
		else this.type = "multi";
	}
	
	/**
	 * Adds listener to the calculationChooseList JComboBox
	 * Calls setCallPutFlagValue with the selected index
	 */
	private void setCalculationChooseListListener(){
		
		calculationChooseList.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent e) {
				
				setCallPutFlagValue(calculationChooseList.getSelectedIndex());
				
			}
			
		});
	}
	
	/**
	 * Sets the value of string callPutFlag depending in JComboBox calculationChooseList selected index
	 * @param index : JComboBox calculationChooseList selected index
	 */
	private void setCallPutFlagValue(int index){
		
		if(index == 0) callPutFlag = "p";
		else callPutFlag = "c";
	}
	
	/**
	 * Adds listener to the dataChooseList JComboBox
	 * Calls displayDataAtIndex with the selected index
	 */
	private void setDataChooseListListener(){
		dataChooseList.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent arg0) {
				
				displayDataAtIndex(dataChooseList.getSelectedIndex() + 1);
				
			}
			
		});
	}
	
	/**
	 * Displays the data set corresponding to the chosen index in the dataChooseList JComboBox
	 * @param index : selected index on the dataChooseList JComboBox
	 */
	private void displayDataAtIndex(int index){
		
		double[] toDisplay = values.get(index);
		
		dataDisplayer.setText("s : " + toDisplay[0] +
				"\nx : " + toDisplay[1] +
				"\nr : " + toDisplay[2] +
				"\nt : " + toDisplay[3] +
				"\nb : " + toDisplay[4] +
				"\nv : " + toDisplay[5]
				);
	}
	
	/**
	 * Sets the listener on the launch button
	 * When clicked, the button hides the window, creates and displays a new ResulWindow and launches the calculation with the chosen parameters 
	 */
	private void setLaunchListener(){
		
		launch.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				
				double[] data = values.get(dataChooseList.getSelectedIndex() + 1);
				r = new ResultWindow(w);
				r.setVisible(true);
				w.setVisible(false);
				
				nSteps = Integer.parseInt(nstepsField.getText());
				nSimulations = Integer.parseInt(nsimulationField.getText());
				
				MonteCarloAbstract m = MonteCarloAbstract.buildMC(type);
				m.build(callPutFlag, data[0], data[1], data[2], data[3], data[4], data[5], nSteps, nSimulations, r);
				Thread t = new Thread(m);
				t.start();
			}
			
		});
	}
	
	/**
	 * Destroys the resultWindows and re-displays the main window
	 */
	public void newTest(){
		r.dispose();
		this.setVisible(true);
	}
}
